package 反射.反射开始;

/**反射
 * ●Reflection "(反射)是被视为动态语言的关键"，反射机制允许程序在执行期
 * 借助于Reflection API取得任何类的内部信息，并能直接操作任意对象的内
 * 部属性及方法。
 * ●加载完类之后，在堆内存的方法区中就产生了一个Class类型的对象(一个
 * 类只有一个Class对象)，这个对象就包含了完整的类的结构信息。我们可
 * 以通过这个对象看到类的结构。这个对象就像一面镜子，透过这个镜子看
 * 到类的结构，所以，我们形象的称之为:反射。
 * 正常方式:引入需要的“包类"名称-->通过new实例化-→取得实例化对象
 * 反射方式:实例化对象 -->getClass()方法 --→得到完整的“包类”名称
 */

 /** 动态语言vs静态语言
 * 1、动态语言
 * 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以
 * 被引进，已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运
 * 行时代码可以根据某些条件改变自身结构。
 * 主要动态语言: Object-C、 C#、JavaScript、 PHP、Python、 Erlang。
 * 2、静态语言
 * 与动态语言相对应的，运行时结构不可变的语言就是静态语言。如Java、C、C++。
 *
 * Java不是动态语言，但Java可以称之为“准动态语言”。即Java有一定的动
 * 态性，我们可以利用反射机制、字节码操作获得类似动态语言的特性。
 * Java的动态性让编程的时候更加灵活!
 */

import 反射.Fs;

import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * ●Java反射机制提供的功能
 * ➢在运行时判断任意一个对象所属的类
 * ➢在运行时构造任意一个类的对象
 * ➢在运行时判断任意一个类所具有的成员变量和方法
 * ➢在运行时获取泛型信息
 * ➢在运行时调用任意一个对象的成员变量和方法
 * ➢在运行时处理注解
 * ➢生成动态代理
 */
public class Main {//反射  大多数用在框架    框架 = 反射 + 注解 + 设计模式
    public static void main(String[] args) throws Exception{
        /**
         * 反射相关的主要API
         * ●java.lang.Class:代表一个类
         * ●java.lang.reflect.Method:代表 类的方法
         * ●java.lang.reflect.Field:代表 类的成员变量
         * ●java.lang.reflect.Constructor:代表类的构造器
         */
        Main m = new Main();
        System.out.println(m.getClass());//class 反射.反射开始.Main
        Class对象的各种实例();
    }
    private static void 通过反射调用类的属性方法等() throws Exception {
        /**
         * get//获取
         * Declared//声明的    加个这  可以获取私有的
         *              给个这   .setAccessible(true);   可以调用私有的
         * Field//属性
         * Method//方法
         * Constructor//构造器
         * Instance   实例
         * invoke    援引
         */
        Fs fs ;
        Class fsc = Fs.class;//相当于Fs fs ///获得这个类   不new  反射源头

        Constructor cons = fsc.getConstructor(String.class, int.class);//获得共有的构造器
        Object tom = cons.newInstance("Tom", 12);//newInstance  new 实例
        fs = (Fs)tom;//不能为空//相当于new Fs();

        System.out.println(fs);//Fs{name='Tom', age=12}
        Field age = fsc.getDeclaredField("age");//获取这个名字叫age的属性
        age.set(fs,10);//将fs里的age属性的值修改
        System.out.println(fs);//Fs{name='Tom', age=10}

        Method show = fsc.getDeclaredMethod("show",int.class);
        //获取方法 第一个是方法名字 之后是参数类型
        show.setAccessible(true);//加这个  可以调用私有的
        Object invoke = show.invoke(fs, 6);//执行fs  的方法
        System.out.println(invoke);

        //通过反射可以调用私用结构
        //调用私有构造器
        Constructor consS = fsc.getDeclaredConstructor(int.class);//获取私有的构造器
        consS.setAccessible(true);
        Fs oS = (Fs) consS.newInstance(15);
        System.out.println(oS);

        //获得私有属性
        Field name = fsc.getDeclaredField("name");
        name.setAccessible(true);
        name.set(oS,"新的名字");
        System.out.println(oS);
    }

    private static void Class对象的各种实例() {
        /**
         * 哪些类型可以有Class对象?
         * (1) class:外部类，成员(成员内部类，静态内部类)，局部内部类，匿名内部类
         * (2) interface: 接口
         * (3) []: 数组.
         * (4) enum: 枚举.
         * (5) annotation: 注解@interface
         * (6)primitive type:基本数据类型
         * (7) void
         */
        Class<Object> c1 = Object.class;//class java.lang.Object
        Class<Comparable> c2 = Comparable.class;//interface java.lang.Comparable
        Class<String[]> c3 = String[].class;//class [L java.lang.String;
        Class<int[][]> c4 = int[][].class;//class [[I
        Class<ElementType> c5 = ElementType.class;//class java.lang.annotation.ElementType
        Class<Override> c6 = Override.class;//interface java.lang.Override
        Class<Integer> c7 = int.class;//int
        Class<Void> c8 = void.class;//void
        System.out.println(c7);
        Class<Class> c9 = Class.class;//class java.lang.Class

        int[] a = new int[10];
        int[] b = new int[100];
        Class<? extends int[]> c10 = a.getClass();
        Class<? extends int[]> c11 = b.getClass();
        // 只要数组的元素类型与维度一样，就是同一个Class
        System.out.println(c10 == c11);//true
    }
}
